package cn.virens.oauth.annotations.handler;

import cn.virens.common.exception.APIException;
import cn.virens.common.spring.annotations.VirAbstractMethodInterceptor;
import cn.virens.oauth.exception.AuthPermException;
import cn.virens.oauth.exception.AuthRoleException;
import cn.virens.oauth.subject.Subject;
import cn.virens.oauth.subject.SubjectUtils;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.core.annotation.AnnotationAttributes;

public class VirAuthMethodInterceptor extends VirAbstractMethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        AnnotationAttributes attributes = findAnnotationAttributes(invocation);

        if (check(attributes, SubjectUtils.getSubject())) {
            return invocation.proceed();
        } else {
            return null;
        }
    }

    /**
     * 执行权限检查：检查角色是否匹配 -> 检查权限是否匹配
     */
    private boolean check(AnnotationAttributes attributes, Subject subject) throws APIException {
        if (subject != null && attributes != null && !testRole(attributes, subject)) {
            throw new AuthRoleException("权限异常:角色未匹配");//
        }

        if (subject != null && attributes != null && !testPerm(attributes, subject)) {
            throw new AuthPermException("权限异常:资源未匹配");//
        }

        return true;
    }

    /**
     * 获取对应的权限标识，如果为空则默认拥有权限，否则回调接口判断是否拥有权限
     */
    private boolean testPerm(AnnotationAttributes attributes, Subject subject) {
        String[] identifiers = attributes.getStringArray("perms");

        if (identifiers != null && identifiers.length > 0) {
            return subject.hasPermissions(identifiers);
        } else {
            return true;
        }
    }

    /**
     * 获取对应的权限标识，如果为空则默认拥有权限，否则回调接口判断是否拥有权限
     */
    private boolean testRole(AnnotationAttributes attributes, Subject subject) {
        String[] identifiers = attributes.getStringArray("roles");

        if (identifiers != null && identifiers.length > 0) {
            return subject.hasRoles(identifiers);
        } else {
            return true;
        }
    }
}
